<html>
  <head>
    <meta charset="UTF-8" />
    <title>spine-threejs</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      body,
      html {
        height: 100%;
      }

      canvas {
        position: absolute;
        width: 100%;
        height: 100%;
      }
    </style>

    <script type="importmap">
    {
        "imports": {
            "three": "https://cdn.jsdelivr.net/npm/three@0.159.0/build/three.module.js",
            "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.159.0/examples/jsm/",
            "spine-threejs": "../dist/esm/spine-threejs.mjs"
        }
    }
    </script>
  </head>

  <body>
    <script type="module">
      import * as THREE from "three";
      import * as spine from "spine-threejs";
      import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

      let scene, camera, renderer;
      let geometry, material, mesh, skeletonMesh, atlas, atlasLoader;
      let assetManager;
      let canvas;
      let controls;
      let lastFrameTime = Date.now() / 1000;

      let pma = true;
      let baseUrl = "/assets/";
      let skeletonFile = "celestial-circus-pro.json";
      let atlasFile = `celestial-circus${pma ? "-pma" : ""}.atlas`;

      function init() {
        // create the THREE.JS camera, scene and renderer (WebGL)
        let width = window.innerWidth,
          height = window.innerHeight;
        camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
        camera.position.y = 0;
        camera.position.z = 800;
        scene = new THREE.Scene();
        renderer = new THREE.WebGLRenderer();
        renderer.setSize(width, height);
        document.body.appendChild(renderer.domElement);
        canvas = renderer.domElement;
        controls = new OrbitControls(camera, renderer.domElement);

        // load the assets required to display the Raptor model
        assetManager = new spine.AssetManager(baseUrl, undefined, pma);
        assetManager.loadText(skeletonFile);
        assetManager.loadTextureAtlas(atlasFile);

        requestAnimationFrame(load);
      }

      function load(name, scale) {
        if (assetManager.isLoadingComplete()) {
          // Add a box to the scene to which we attach the skeleton mesh
          geometry = new THREE.BoxGeometry(200, 200, 200);
          material = new THREE.MeshBasicMaterial({
            color: 0xff0000,
            wireframe: true,
          });
          mesh = new THREE.Mesh(geometry, material);
          scene.add(mesh);

          // Load the texture atlas using name.atlas and name.png from the AssetManager.
          // The function passed to TextureAtlas is used to resolve relative paths.
          atlas = assetManager.require(atlasFile);

          // Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
          atlasLoader = new spine.AtlasAttachmentLoader(atlas);

          // Create a SkeletonJson instance for parsing the .json file.
          let skeletonJson = new spine.SkeletonJson(atlasLoader);

          // Set the scale to apply during parsing, parse the file, and create a new skeleton.
          skeletonJson.scale = 0.4;
          let skeletonData = skeletonJson.readSkeletonData(
            assetManager.require(skeletonFile)
          );

            // Create a SkeletonMesh from the data and attach it to the scene
            skeletonMesh = new spine.SkeletonMesh({
              skeletonData,
              materialFactory: (parameters) => {
                return new THREE.MeshBasicMaterial({
                  ...parameters,
                  // transparent: true,
                  // depthWrite: true,
                  // depthTest: true,
                  // alphaTest: 0.001,
                  // vertexColors: true,
                });
              },
              twoColorTint: false,
            });
            skeletonMesh.state.setAnimation(0, "swing", true);
            skeletonMesh.state.setAnimation(1, "eyeblink-long", true);
            mesh.add(skeletonMesh);

          skeletonMesh.position.y = -200;

          requestAnimationFrame(render);
        } else requestAnimationFrame(load);
      }

      let lastTime = Date.now();
      function render() {
        // calculate delta time for animation purposes
        let now = Date.now() / 1000;
        let delta = now - lastFrameTime;
        lastFrameTime = now;

        // resize canvas to use full page, adjust camera/renderer
        resize();

        // Update orbital controls
        controls.update();

        // update the animation
        skeletonMesh.update(delta);

        // render the scene
        renderer.render(scene, camera);

        requestAnimationFrame(render);
      }

      function resize() {
        let w = window.innerWidth;
        let h = window.innerHeight;
        if (canvas.width != w || canvas.height != h) {
          canvas.width = w;
          canvas.height = h;
        }

        camera.aspect = w / h;
        camera.updateProjectionMatrix();

        renderer.setSize(w, h);
      }

      init();

    </script>
  </body>
</html>